import 'dart:async';
import 'dart:typed_data';
import 'package:flutter/cupertino.dart';
import 'package:flutter_sound/flutter_sound.dart';
import 'controller_stream.dart';
import 'speex_ffi.dart';

class RecordUtil {
  /// 单例实例：全局唯一的录音工具，避免多录音器冲突
  static final RecordUtil instance = RecordUtil._();

  /// 私有构造函数：禁止外部创建实例
  RecordUtil._();

  /// 录音状态标记：true表示正在录音，false表示已停止
  bool _isRecording = false;

  /// 帧状态：标记当前输出的音频帧类型（0=首帧，1=中帧，2=尾帧）
  int frameState = ControllerChannel.firstFrame;

  /// FlutterSound录音器实例：封装系统底层录音能力
  final FlutterSoundRecorder _recorder = FlutterSoundRecorder();

  /// 音频数据流：接收录音器输出的PCM原始数据
  Stream<Uint8List>? _audioStream;

  /// 音频流控制器：用于将录音数据转发到自定义流（_audioStream）
  StreamController<Uint8List>? _audioStreamController;


  /// 初始化录音器：打开录音设备，需在录音前调用
  /// 注：需提前申请麦克风权限（AndroidManifest/iOS Info.plist配置）
  Future<void> initRecorder() async {
    await _recorder.openRecorder();
  }

  /// 停止录音：释放录音资源，标记尾帧状态
  Future<void> stopRecord() async {
    debugPrint("停止录音 - stopRecord");
    // 停止录音器
    await _recorder.stopRecorder();
    // 标记当前帧为尾帧（通知服务端传输结束）
    frameState = ControllerChannel.lastFrame;
    // 关闭流控制器：释放资源，避免内存泄露
    _audioStreamController?.close();
    // 置空流相关变量：重置状态
    _audioStreamController = null;
    _audioStream = null;
    // 更新录音状态为停止
    _isRecording = false;
  }

  /// 开始录音并监听音频数据：将PCM原始数据编码为Speex，通过回调输出
  /// @param callback：接收编码后音频帧和帧大小的回调函数
  Future<void> listen(Future<void> Function(Uint8List, int) callback,
      {required Function(Object) onError}) async {
    // 先停止现有录音：避免重复录音
    await stopRecord();
    // 更新录音状态为正在录音
    _isRecording = true;
    // 初始化流控制器：用于接收录音器输出的PCM数据
    _audioStreamController = StreamController<Uint8List>();
    // 绑定数据流：从控制器获取PCM原始数据
    _audioStream = _audioStreamController!.stream;

    // 启动录音器：配置录音参数并绑定输出流
    await _recorder.startRecorder(
      toStream: _audioStreamController!.sink, // 录音数据输出到流控制器
      codec: Codec.pcm16, // 录音编码格式：16位PCM（无压缩原始数据）
      numChannels: 1,     // 声道数：单声道（语音场景常用）
      sampleRate: 16000,  // 采样率：16kHz（语音识别标准采样率）
    );

    // 初始化Speex编码器：将PCM原始数据压缩为Speex格式（减少传输带宽）
    final encoder = SpeexEncoderFFI();
    // 计算Speex帧大小：PCM16为2字节/样本，故帧大小 = 编码器帧大小 × 2
    final frameSize = encoder.frameSize * 2;
    // 音频数据缓冲区：用于累积PCM数据，达到帧大小后再编码
    Uint8List buffer = Uint8List(0);
    // 初始帧状态设为首页（第一个编码帧为首页）
    frameState = ControllerChannel.firstFrame;
    // 异步任务队列：确保编码和发送操作串行执行，避免数据乱序
    Future<void> recognitionQueue = Future.value();
    // 监听PCM原始数据流：处理每一段录音数据
    _audioStream!.listen((Uint8List data) {
      // 累积PCM数据到缓冲区
      buffer = Uint8List.fromList([...buffer, ...data]);

      // 当缓冲区数据达到Speex帧大小时，进行编码和发送
      while (buffer.length >= frameSize) {
        // 截取一帧PCM数据（长度=frameSize）
        final frame = buffer.sublist(0, frameSize);
        // PCM数据编码为Speex格式
        final encoded = encoder.encode(frame);

        // 串行执行编码后数据的发送：通过队列确保顺序
        recognitionQueue = recognitionQueue.then((_) async {
          // 调用外部回调，传递Speex编码数据和帧大小
          try {
            await callback(encoded, frameState);
          } catch (e) {
            debugPrint("录音出现错误：$e");
            onError(e);
          }
          // 首帧发送后，后续帧设为中帧
          frameState = ControllerChannel.continueFrame;
        });

        // 移除已处理的PCM数据，保留剩余数据
        buffer = buffer.sublist(frameSize);
      }
    });
  }
}